package gameElements;


import java.util.Random;

public class Map {

	private Room[][] roomArray;


	private static final int MAX_ROOMS = 20;
	//important note: since the size of the roomArray is 2*MAX_ROOMS + 1
	//MAX_ROOMS is often used to access the middle of the array

	private boolean stairsExist;
	private boolean elevatorExists;
	private Random generator;

	private int numRooms = 0;

	public Map(int seed){
		//2 * MAX_ROOMS + 1 means that the rooms generated can never get outside the array
		roomArray = new Room[2 * MAX_ROOMS + 1][2 * MAX_ROOMS + 1];

		generator = new Random(seed);	
		stairsExist = false;
		elevatorExists = false;
	}


	public void generateMap(int level){
		//see google doc for room generation documentation




		//this is the center of the array where the start room should be
		//the start room should have only one door that is an entrance to the building

		roomArray[MAX_ROOMS][MAX_ROOMS] = new Room(Room.Type.START);
		roomArray[MAX_ROOMS][MAX_ROOMS].addDoor(0);
		numRooms++;

		roomArray[MAX_ROOMS - 1][MAX_ROOMS] = new Room(Room.Type.NORMAL);
		numRooms++;
		roomArray[MAX_ROOMS - 2][MAX_ROOMS] = new Room(Room.Type.NORMAL);
		numRooms++;
		
		//first create rooms, do not assign them doors yet,
		//doors depend on adjacent rooms which may or may not exist so
		//determine the location of all rooms first

		while(numRooms < MAX_ROOMS){
			//randomize the i and j values for random placement
			int i = generator.nextInt(MAX_ROOMS * 2);
			int j = generator.nextInt(MAX_ROOMS * 2);
			
			//set rooms below start to null
			for (int d = 1; d < MAX_ROOMS; d++) {
				if(roomArray[MAX_ROOMS + d][MAX_ROOMS] != null){
					roomArray[MAX_ROOMS + d][MAX_ROOMS] = null;
					numRooms--;
				}
				
			}

			//create rooms
			if(countAdjacentRoomExists(i, j, Room.Type.NORMAL) > 0){
				if(roomArray[i][j] == null){ //room doesn't already exist					
					roomArray[i][j] = new Room(Room.Type.NORMAL); //randomize type below					
					numRooms++;					
				}
			}
		}//end room generation while



		if(level == 2 || level == 0){

			//remove exterior rooms of type normal based on randomness 
			for (int i = 0; i < roomArray.length; i++) {
				for (int j = 0; j < roomArray.length; j++) {
					if(countAdjacentRoomExists(i, j, Room.Type.NORMAL) < 3 && generator.nextInt(10) > 3)
					{
						if(countAdjacentRoomExists(i, j, Room.Type.NORMAL) < 3 && generator.nextInt(6) > 3){
							roomArray[i][j] = null;
						}
					}
				}
			}			
		}// end if( level == 2)

		//remove rooms that are not connected to any other rooms
		for (int i = 0; i < roomArray.length; i++) {
			for (int j = 0; j < roomArray.length; j++) {
				if(countAdjacentRoomExists(i, j, Room.Type.NORMAL) == 0)
					roomArray[i][j] = null;
			}
		}

		//randomly add elevator and stairs	
		int typeChance = generator.nextInt(10);

		while(!elevatorExists && !stairsExist){
			for (int i = 0; i < roomArray.length; i++) {
				for (int j = 0; j < roomArray.length; j++) {
					if(roomArray[i][j] == null){						
						if(typeChance == 0 && !elevatorExists && j != MAX_ROOMS){ //elevator is not in line with start
							roomArray[i][j].setType(Room.Type.ELEVATOR);
							elevatorExists = true;
						}
						else if(typeChance == 1 && !stairsExist && j != MAX_ROOMS){
							roomArray[i][j].setType(Room.Type.STAIR);
							stairsExist = true;
						}
						//rooms not selected remain normal
						
						typeChance = generator.nextInt(10);
					}

				}
			}
		}
		
		

	}

	public int countAdjacentRoomExists(int i, int j, Room.Type type){
		int numAdjacentRooms = 0;
		if(i > 0 && i < roomArray.length - 1 && j > 0 && j < roomArray.length - 1){

			if(roomArray[i - 1][j] != null && roomArray[i - 1][j].getType() == type)// left of current
				numAdjacentRooms++;
			if(roomArray[i + 1][j] != null && roomArray[i + 1][j].getType() == type)// right of current
				numAdjacentRooms++;
			if(roomArray[i][j - 1] != null && roomArray[i][j - 1].getType() == type)//above current
				numAdjacentRooms++;
			if(roomArray[i][j + 1] != null &&roomArray[i][j + 1].getType() == type)// below current
				numAdjacentRooms++;
		}
		return numAdjacentRooms;
	}

	public boolean[] locateAdjacentRooms(int i, int j, Room.Type type){
		boolean[] locations = new boolean[4]; // north, east, south, west


		if(i > 0 && i < roomArray.length - 1 && j > 0 && j < roomArray.length - 1){

			if(roomArray[i - 1][j] != null && roomArray[i - 1][j].getType() == type)// left of current
				locations[0] = true;
			if(roomArray[i + 1][j] != null && roomArray[i + 1][j].getType() == type)// right of current
				locations[2] = true;
			if(roomArray[i][j - 1] != null && roomArray[i][j - 1].getType() == type)//above current				
				locations[3] = true;
			if(roomArray[i][j + 1] != null && roomArray[i][j + 1].getType() == type)// below current				
				locations[1] = true;
		}
		return locations;
	}

	public void createDoors(){
		for (int i = 0; i < roomArray.length - 1; i++) {
			for (int j = 0; j < roomArray.length - 1; j++) {



				boolean[] possibleLocations = new boolean[4];
				if(roomArray[i][j] != null){
					possibleLocations = locateAdjacentRooms(i, j, Room.Type.NORMAL);
					if(possibleLocations[0]){ //room to the north
						if(! possibleLocations[1] && ! possibleLocations[2] && ! possibleLocations[3]){//only connected at north, must have door
							roomArray[i][j].addDoor(0);
						}
						else{
							while(roomArray[i][j].getNumDoors() < 2){ //every room has at least two doors
								for(int k = 0; k < possibleLocations.length; k++)
									if(possibleLocations[k])
										if(generator.nextInt(5) > 3)
											roomArray[i][j].addDoor(k);
							}
						}
					}//end north
					else if(possibleLocations[1]){ // room to east
						if(! possibleLocations[0] && ! possibleLocations[2] && ! possibleLocations[3]){
							roomArray[i][j].addDoor(1);
						}
						else{
							while(roomArray[i][j].getNumDoors() < 2){
								for(int k = 0; k < possibleLocations.length; k++)
									if(possibleLocations[k])
										if(generator.nextInt(5) > 3)
											roomArray[i][j].addDoor(k);
							}
						}						
					}//end east
					else if(possibleLocations[2]){ //room to south
						if(! possibleLocations[0] && ! possibleLocations[1] && ! possibleLocations[3]){
							roomArray[i][j].addDoor(2);
						}
						else{
							while(roomArray[i][j].getNumDoors() < 2){
								for(int k = 0; k < possibleLocations.length; k++)
									if(possibleLocations[k])
										if(generator.nextInt(5) > 3)
											roomArray[i][j].addDoor(k);
							}
						}						
					}//end south
					else if(possibleLocations[3]){ //room to west
						if(! possibleLocations[0] && ! possibleLocations[1] && ! possibleLocations[2]){
							roomArray[i][j].addDoor(3);
						}
						else{
							while(roomArray[i][j].getNumDoors() < 2){
								for(int k = 0; k < possibleLocations.length; k++)
									if(possibleLocations[k])
										if(generator.nextInt(5) > 3)
											roomArray[i][j].addDoor(k);
							}
						}						
					}//end west


				}//end if(roomArray[i][j] != null)
			}//end for
		}// end for

		//start room is only connected at north
		roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(1);
		roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(2);
		roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(3);

		//must do this once doors are finished being created
		//creates doors on other side of wall in rooms
		for (int i = 0; i < roomArray.length; i++) {
			for (int j = 0; j < roomArray.length; j++) {

				//start must only have north door
				roomArray[MAX_ROOMS][MAX_ROOMS].addDoor(0);
				roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(1);
				roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(2);
				roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(3);

				if(roomArray[i][j] != null){
					if(i > 0 && i < MAX_ROOMS * 2 && j > 0 && j < MAX_ROOMS * 2){
						if(roomArray[i][j - 1] != null && roomArray[i][j - 1].getDoor(1)){//room to the west has a door to the current room
							//must have door to that room (door on either side of wall)
							roomArray[i][j].addDoor(3);
						}
						if(roomArray[i][j + 1] != null && roomArray[i][j + 1].getDoor(3)){//room to east has door to current room
							roomArray[i][j].addDoor(1);
						}
						if(roomArray[i - 1][j] != null && roomArray[i - 1][j].getDoor(2)){
							roomArray[i][j].addDoor(0);
						}
						if(roomArray[i + 1][j] != null && roomArray[i + 1][j].getDoor(0)){
							roomArray[i][j].addDoor(2);
						}
					}
				}
			}
		}

		//start must only have north door
		roomArray[MAX_ROOMS][MAX_ROOMS].addDoor(0);
		roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(1);
		roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(2);
		roomArray[MAX_ROOMS][MAX_ROOMS].removeDoor(3);
	}

	public Room[][] getRoomArray(){
		return roomArray;
	}
	public static int getMaxRooms(){
		return MAX_ROOMS;
	}
}
